<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>作用域</title>
</head>

<body>
    <p>作用域（scope）规定了变量能够被访问的“范围”，离开了这个“范围”变量便不能被访问</p>
    <p>作用域分为全局作用域和局部作用域。</p>
    <p>局部作用域分为函数作用域和块作用域。</p>
    <p>
        函数作用域: <br>
        在函数内部声明的变量只能在函数内部被访问，外部无法直接访问。</p>
    <p>
        总结：<br>

        1. 函数内部声明的变量，在函数外部无法被访问 <br>
        2. 函数的参数也是函数内部的局部变量 <br>
        3. 不同函数内部声明的变量无法互相访问 <br>
        4. 函数执行完毕后，函数内部的变量实际被清空了
    </p>
    <p>
        块作用域: <br>
        在 JavaScript 中使用 {} 包裹的代码称为代码块，代码块内部声明的变量外部将【有可能】无法被访问。
    </p>
    <p>JavaScript 中除了变量外还有常量，常量与变量本质的区别是【常量必须要有值且不允许被重新赋值】，常量值为对象时其属性和方法允许重新赋值。</p>

    <p>
        总结： <br>

        1. let 声明的变量会产生块作用域，var 不会产生块作用域 <br>
        2. const 声明的常量也会产生块作用域 <br>
        3. 不同代码块之间的变量无法互相访问 <br>
        4. 推荐使用 let 或 const <br>

        注：开发中 let 和 const 经常不加区分的使用，如果担心某个值会不小被修改时，则只能使用 const 声明成常量。
    </p>

    <p>
        全局作用域<br>

        script 标签和.js 文件的【最外层】就是所谓的全局作用域，在此声明的变量在函数内部也可以被访问。<br>
        全局作用域中声明的变量，任何其它作用域都可以被访问
    </p>
    <p>
        总结：<br>

        1. 为 window 对象动态添加的属性默认也是全局的，不推荐！<br>
        2. 函数中未使用任何关键字声明的变量为全局变量，不推荐！！！<br>
        3. 尽可能少的声明全局变量，防止全局变量被污染 <br>

        JavaScript 中的作用域是程序被执行时的底层机制，了解这一机制有助于规范代码书写习惯，避免因作用域导致的语法错误。

    </p>
    <script>
        // 函数作用域
        function counter(x, y) {
            const s = x + y
            console.log(s); // 5

        }
        counter(2, 3) // 调用counter()函数
        // console.log(s); // × ReferenceError: s is not defined

        // 块作用域
        {
            let age = 18;
            console.log(age); // 18  age 只能在该代码块中被访问
        }
        // console.log(age); // × ReferenceError: age is not defined 报错 超出了 age 的作用域

        let flag = true;
        if (flag) {
            let str = 'hello world!'
            console.log(str);  // hello world!  str 只能在该代码块中被访问
        }
        // console.log(str); // × 超出了 atr 的作用域

        for (let t = 0; t < 6; t++) {
            console.log(t);  // 0 1 2 3 4 5  t 只能在该代码块中被访问
        }
        // console.log(t); // ×  超出了 t 的作用域

        // JavaScript 中除了变量外还有常量，常量与变量本质的区别是【常量必须要有值且不允许被重新赋值】，
        // 常量值为对象时其属性和方法允许重新赋值。

        const version = '1.0.0' // const定义常量必须要有值
        console.log(version); // 1.0.0 
        // version = '1.0.1' // x TypeError: Assignment to constant variable.
        // 不能重新赋值

        //常量为对象类型
        const user = {
            name: '小明',
            age: 18
        }
        console.log(user.name);
        console.log(user.age + '岁');

        // user = {} // x TypeError: Assignment to constant variable.
        // 不能重新赋值

        console.log(user.name = '小小明');
        console.log(user.gender = '男');



        // 此处是全局
        function sayHi() {
            // 此处为局部
        }
        // 此处为全局


        const name = '小明' // 全局变量name

        //函数作用域中访问全局
        function sayHi() {
            // 此处为局部
            console.log('你好' + name);
        }

        // 全局变量flag2 和 x
        const flag2 = true
        let a = 10


        // 块作用域中访问全局
        if (flag2) {
            let b = 5
            console.log(a + b); // 15
        }



    </script>

</body>

</html>